﻿using System;
using System.Collections.Generic;
using UtilsExtensionsAndHelpers.Helpers;
using UtilsExtensionsAndHelpers.Helpers.Implimentations;

namespace UtilsExtensionsAndHelpers.Utils.Implimentations
{
    public class ObjectFactory : IObjectFactory
    {
        protected Dictionary<Type, ClassInfo> _bindings = new Dictionary<Type, ClassInfo>();

        #region Instance
        public TInterface Instance<TInterface>(Type type)
        {
            if (!Exists(type)) return default(TInterface);

            return (TInterface) (_bindings[type].Instance ?? (_bindings[type].Instance = _bindings[type].Constructor()));
        }
        public TInterface Instance<TInterface>()
        {
            var type = typeof(TInterface);
            return Instance<TInterface>(type);
        }
        public IEnumerable<TInterface> InstanceList<TInterface>()
        {
            var type = typeof(IList<TInterface>);

            if (!Exists(type)) return default(IList<TInterface>);

            return (IList<TInterface>)(_bindings[type].Instance ?? (_bindings[type].Instance = _bindings[type].Constructor()));
        }
        #endregion

        #region New
        public TInterface New<TInterface>(Type type)
        {
            if (Exists(type)) return (TInterface)_bindings[type].Constructor();
            return default(TInterface);
        }
        public TInterface New<TInterface>()
        {
            var type = typeof(TInterface);
            return New<TInterface>(type);
        }

        public IEnumerable<TInterface> NewList<TInterface>()
        {
            var type = typeof(IList<TInterface>);

            if (Exists(type)) return (IList<TInterface>)_bindings[type].Constructor();
            return default(IList<TInterface>);
        }
        #endregion

        #region Bind
        public void Bind<TInterface>(Func<Object> constructor)
        {
            var type = typeof(TInterface);
            Bind(type, constructor);
        }
        public void Bind(Type type, Func<Object> constructor)
        {
            if (_bindings.ContainsKey(type)) _bindings.Remove(type);
            _bindings.Add(type, new ClassInfo { Constructor = constructor });
        }
        #endregion
        
        protected bool Exists(Type type)
        {
            return _bindings.ContainsKey(type);
        }

        protected class ClassInfo
        {
            private Object _instance;
            public Func<Object> Constructor { get; set; }
            public Object Instance
            {
                get { return _instance ?? (_instance = Constructor()); }
                set { _instance = value; }
            }
        }


        public void BindFileBackedPersistable<TInterface>(string filePath, int refreshRateInMinutes)
        {
            BindFileBackedPersistable(typeof(TInterface),filePath, refreshRateInMinutes);
        }

        public void BindFileBackedPersistable(Type type, string filePath, int refreshRateInMinutes)
        {
            
        }

        protected class FileBackedInfo<T>
        {
            private static ISerializationHelper _serializationHelper = new SerializationHelper();

            public string FilePath { get; set; }
            public int RefreshRateInMinutes { get; set; }
            public DateTime LastReadTime { get; set; }
            public string PreviousMd5FileHash { get; set; }
            public T Instance { get; set; }
            
            public T GetInstance()
            {
                var isTimeForUpdate = LastReadTime.AddMinutes(RefreshRateInMinutes) > DateTime.Now;
                var md5HashesDontMatch = false;

                if (isTimeForUpdate || md5HashesDontMatch)
                {
                    Instance = _serializationHelper.DeserializeFromFile<T>(FilePath);
                }
                
                return Instance;
            }
        }
    }
}
